﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows.Input;
using Fantacid303.ProcessAffinityControl.Manager.Extensions;
using Fantacid303.ProcessAffinityControl.Config;
using Fantacid303.ProcessAffinityControl.Common;
using System.IO;
using System.Windows;
using Fantacid303.ProcessAffinityControl.Manager.Properties;

namespace Fantacid303.ProcessAffinityControl.Manager.MainWindowViewModels
{
	/// <summary>
	/// Represents the View Model of the whole configuration
	/// </summary>
	partial class ConfigurationViewModel : ViewModelBase
	{
		private uint interval;
		private object selectedTreeObject;
		private ObservableCollection<ConfigurationEntryViewModel> configurationEntries;
		private ConfigurationEntryViewModel selectedConfiguration;
		private ObservableCollection<ExcludedProcessViewModel> excludedProcesses;
		private ObservableCollection<ProcessViewModel> runningProcesses;
		private string statusMessage;
		private ConfigurationManager configurationManager = new ConfigurationManager();

		/// <summary>
		/// Initializes a new instance of the <see cref="ConfigurationViewModel"/> class.
		/// </summary>
		public ConfigurationViewModel()
		{
			this.AddNewEntryCommand = new MyAddNewEntryCommand(this);
			this.RefreshProcessListCommand = new MyRefreshProcessListCommand(this);
			this.SaveCommand = new MySaveCommand(this);
			this.IncreaseIntervalCommand = new MyIncreaseIntervalCommand(this);
			this.DecreaseIntervalCommand = new MyDecreaseIntervalCommand(this);

			this.StatusMessage = string.Empty;


			this.UpdateConfigurationFromManager();
		}

		/// <summary>
		/// Gets the status message
		/// </summary>
		/// <value>The status message.</value>
		public string StatusMessage
		{
			get { return statusMessage; }
			 set
			{
				if (statusMessage == value)
					return;

				statusMessage = value;
				this.OnPropertyChanged("StatusMessage");
			}
		}

		/// <summary>
		/// Gets or sets the scan interval in seconds.
		/// </summary>
		/// <value>The scan interval.</value>
		public uint Interval
		{
			get { return interval; }
			set
			{
				if (interval == value)
					return;

				interval = value;
				this.OnPropertyChanged("Interval");
			}
		}


		/// <summary>
		/// Gets or sets the selected tree object.
		/// </summary>
		/// <value>The selected tree object.</value>
		public object SelectedTreeObject
		{
			get { return selectedTreeObject; }
			set
			{
				if (selectedTreeObject == value)
					return;

				selectedTreeObject = value;
				this.OnPropertyChanged("SelectedTreeObject");
			}
		}

		/// <summary>
		/// Updates the configuration from manager configuration manager
		/// </summary>
		private void UpdateConfigurationFromManager()
		{
			try
			{
				this.configurationManager.ReadConfig();
			}
			catch (FileNotFoundException)
			{
				if (MessageBoxResult.No == MessageBox.Show(Messages.ConfigFileNotFoundCreateDefaultConfig, "Configuration Not Found", MessageBoxButton.YesNo, MessageBoxImage.Question))
				{
					Application.Current.Shutdown();
					return;
				}
				else
				{
					this.configurationManager.CreateDefaultConfiguration();
				}
			}

			var config = this.configurationManager.Configuration;
			foreach (var entry in config.ConfigurationEntries)
			{
				var modelEntry = new ConfigurationEntryViewModel(this) { IsActive = entry.IsActive, Name = entry.Name };

				foreach (var rule in entry.Rules)
				{
					var modelRule = new ConfigurationRuleViewModel(modelEntry) { AffinityType = rule.ProcessorAffinityType, ProcessName = rule.ProcessName };
					#region mask mapping
					modelRule.CustomMaskProcessor0 = (rule.AffinityMask & ((ulong)1 << 0)) != 0;
					modelRule.CustomMaskProcessor1 = (rule.AffinityMask & ((ulong)1 << 1)) != 0;
					modelRule.CustomMaskProcessor2 = (rule.AffinityMask & ((ulong)1 << 2)) != 0;
					modelRule.CustomMaskProcessor3 = (rule.AffinityMask & ((ulong)1 << 3)) != 0;
					modelRule.CustomMaskProcessor4 = (rule.AffinityMask & ((ulong)1 << 4)) != 0;
					modelRule.CustomMaskProcessor5 = (rule.AffinityMask & ((ulong)1 << 5)) != 0;
					modelRule.CustomMaskProcessor6 = (rule.AffinityMask & ((ulong)1 << 6)) != 0;
					modelRule.CustomMaskProcessor7 = (rule.AffinityMask & ((ulong)1 << 7)) != 0;
					modelRule.CustomMaskProcessor8 = (rule.AffinityMask & ((ulong)1 << 8)) != 0;
					modelRule.CustomMaskProcessor9 = (rule.AffinityMask & ((ulong)1 << 9)) != 0;
					modelRule.CustomMaskProcessor10 = (rule.AffinityMask & ((ulong)1 << 10)) != 0;
					modelRule.CustomMaskProcessor11 = (rule.AffinityMask & ((ulong)1 << 11)) != 0;
					modelRule.CustomMaskProcessor12 = (rule.AffinityMask & ((ulong)1 << 12)) != 0;
					modelRule.CustomMaskProcessor13 = (rule.AffinityMask & ((ulong)1 << 13)) != 0;
					modelRule.CustomMaskProcessor14 = (rule.AffinityMask & ((ulong)1 << 14)) != 0;
					modelRule.CustomMaskProcessor15 = (rule.AffinityMask & ((ulong)1 << 15)) != 0;
					modelRule.CustomMaskProcessor16 = (rule.AffinityMask & ((ulong)1 << 16)) != 0;
					modelRule.CustomMaskProcessor17 = (rule.AffinityMask & ((ulong)1 << 17)) != 0;
					modelRule.CustomMaskProcessor18 = (rule.AffinityMask & ((ulong)1 << 18)) != 0;
					modelRule.CustomMaskProcessor19 = (rule.AffinityMask & ((ulong)1 << 19)) != 0;
					modelRule.CustomMaskProcessor20 = (rule.AffinityMask & ((ulong)1 << 20)) != 0;
					modelRule.CustomMaskProcessor21 = (rule.AffinityMask & ((ulong)1 << 21)) != 0;
					modelRule.CustomMaskProcessor22 = (rule.AffinityMask & ((ulong)1 << 22)) != 0;
					modelRule.CustomMaskProcessor23 = (rule.AffinityMask & ((ulong)1 << 23)) != 0;
					modelRule.CustomMaskProcessor24 = (rule.AffinityMask & ((ulong)1 << 24)) != 0;
					modelRule.CustomMaskProcessor25 = (rule.AffinityMask & ((ulong)1 << 25)) != 0;
					modelRule.CustomMaskProcessor26 = (rule.AffinityMask & ((ulong)1 << 26)) != 0;
					modelRule.CustomMaskProcessor27 = (rule.AffinityMask & ((ulong)1 << 27)) != 0;
					modelRule.CustomMaskProcessor28 = (rule.AffinityMask & ((ulong)1 << 28)) != 0;
					modelRule.CustomMaskProcessor29 = (rule.AffinityMask & ((ulong)1 << 29)) != 0;
					modelRule.CustomMaskProcessor30 = (rule.AffinityMask & ((ulong)1 << 30)) != 0;
					modelRule.CustomMaskProcessor31 = (rule.AffinityMask & ((ulong)1 << 31)) != 0;
					modelRule.CustomMaskProcessor32 = (rule.AffinityMask & ((ulong)1 << 32)) != 0;
					modelRule.CustomMaskProcessor33 = (rule.AffinityMask & ((ulong)1 << 33)) != 0;
					modelRule.CustomMaskProcessor34 = (rule.AffinityMask & ((ulong)1 << 34)) != 0;
					modelRule.CustomMaskProcessor35 = (rule.AffinityMask & ((ulong)1 << 35)) != 0;
					modelRule.CustomMaskProcessor36 = (rule.AffinityMask & ((ulong)1 << 36)) != 0;
					modelRule.CustomMaskProcessor37 = (rule.AffinityMask & ((ulong)1 << 37)) != 0;
					modelRule.CustomMaskProcessor38 = (rule.AffinityMask & ((ulong)1 << 38)) != 0;
					modelRule.CustomMaskProcessor39 = (rule.AffinityMask & ((ulong)1 << 39)) != 0;
					modelRule.CustomMaskProcessor40 = (rule.AffinityMask & ((ulong)1 << 40)) != 0;
					modelRule.CustomMaskProcessor41 = (rule.AffinityMask & ((ulong)1 << 41)) != 0;
					modelRule.CustomMaskProcessor42 = (rule.AffinityMask & ((ulong)1 << 42)) != 0;
					modelRule.CustomMaskProcessor43 = (rule.AffinityMask & ((ulong)1 << 43)) != 0;
					modelRule.CustomMaskProcessor44 = (rule.AffinityMask & ((ulong)1 << 44)) != 0;
					modelRule.CustomMaskProcessor45 = (rule.AffinityMask & ((ulong)1 << 45)) != 0;
					modelRule.CustomMaskProcessor46 = (rule.AffinityMask & ((ulong)1 << 46)) != 0;
					modelRule.CustomMaskProcessor47 = (rule.AffinityMask & ((ulong)1 << 47)) != 0;
					modelRule.CustomMaskProcessor48 = (rule.AffinityMask & ((ulong)1 << 48)) != 0;
					modelRule.CustomMaskProcessor49 = (rule.AffinityMask & ((ulong)1 << 49)) != 0;
					modelRule.CustomMaskProcessor50 = (rule.AffinityMask & ((ulong)1 << 50)) != 0;
					modelRule.CustomMaskProcessor51 = (rule.AffinityMask & ((ulong)1 << 51)) != 0;
					modelRule.CustomMaskProcessor52 = (rule.AffinityMask & ((ulong)1 << 52)) != 0;
					modelRule.CustomMaskProcessor53 = (rule.AffinityMask & ((ulong)1 << 53)) != 0;
					modelRule.CustomMaskProcessor54 = (rule.AffinityMask & ((ulong)1 << 54)) != 0;
					modelRule.CustomMaskProcessor55 = (rule.AffinityMask & ((ulong)1 << 55)) != 0;
					modelRule.CustomMaskProcessor56 = (rule.AffinityMask & ((ulong)1 << 56)) != 0;
					modelRule.CustomMaskProcessor57 = (rule.AffinityMask & ((ulong)1 << 57)) != 0;
					modelRule.CustomMaskProcessor58 = (rule.AffinityMask & ((ulong)1 << 58)) != 0;
					modelRule.CustomMaskProcessor59 = (rule.AffinityMask & ((ulong)1 << 59)) != 0;
					modelRule.CustomMaskProcessor60 = (rule.AffinityMask & ((ulong)1 << 60)) != 0;
					modelRule.CustomMaskProcessor61 = (rule.AffinityMask & ((ulong)1 << 61)) != 0;
					modelRule.CustomMaskProcessor62 = (rule.AffinityMask & ((ulong)1 << 62)) != 0;
					modelRule.CustomMaskProcessor63 = (rule.AffinityMask & ((ulong)1 << 63)) != 0;
					#endregion
					modelEntry.Rules.Add(modelRule);
				}

				this.ConfigurationEntries.Add(modelEntry);
			}

			this.ExcludedProcesses.Clear();
			foreach (var excludedProcess in config.ProcessIgnoreList)
				this.ExcludedProcesses.Add(new ExcludedProcessViewModel(this) { Name = excludedProcess });

			this.Interval = config.Interval;
		}
		
        
        /// <summary>
        /// Gets or sets the selected <see cref="ConfigurationEntry"/> from/to the UI
        /// </summary>
        public ConfigurationEntryViewModel SelectedConfiguration
		{
			get { return selectedConfiguration; }
			set
			{
				if (selectedConfiguration == value)
					return;

				selectedConfiguration = value;
				this.OnPropertyChanged("SelectedConfiguration");
			}
		}


        /// <summary>
        /// Gets the available list of <see cref="ConfigurationEntry"/>.
        /// </summary>
		public ObservableCollection<ConfigurationEntryViewModel> ConfigurationEntries
		{
			get
			{
				if (configurationEntries == null)
                    configurationEntries = new ObservableCollection<ConfigurationEntryViewModel>();
				return configurationEntries;
			}
		}

		
        /// <summary>
		/// Gets the available list of <see cref="ExcludedProcessViewModel"/>.
        /// </summary>
		public ObservableCollection<ExcludedProcessViewModel> ExcludedProcesses
		{
			get
			{
				if (excludedProcesses == null)
					excludedProcesses = new ObservableCollection<ExcludedProcessViewModel>();
				return excludedProcesses;
			}
		}
	
		
        /// <summary>
		/// Gets the available list of <see cref="ProcessViewModel"/>.
        /// </summary>
		public ObservableCollection<ProcessViewModel> RunningProcesses
		{
			get
			{
				if (runningProcesses == null)
					runningProcesses = new ObservableCollection<ProcessViewModel>();
				return runningProcesses;
			}
		}
	}
}